﻿//Created: 3/14/2013 @ 10:11pm by Dagradt
//Last changed date: 3/15/2013 @ 7:35pm by Dagradt

using Action = Styx.TreeSharp.Action;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.TreeSharp;
using Styx.WoWInternals.WoWObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using Styx.WoWInternals;
using Styx.Common;

namespace Death_Knight_Frost__2H
{
    public class Main : CombatRoutine
    {
        public override string Name { get { return "Death Knight(Frost) 2H"; } }
        public override WoWClass Class { get { return WoWClass.DeathKnight; } }
        LocalPlayer Me { get { return StyxWoW.Me; } }

        private Composite _preCombatBuffs, _combatBuffs, _Heal, _Combat;
        public override Composite PreCombatBuffBehavior { get { return _preCombatBuffs; } }
        public override Composite CombatBuffBehavior { get { return _combatBuffs; } }
        public override Composite HealBehavior { get { return _Heal; } }
        public override Composite CombatBehavior { get { using (StyxWoW.Memory.AcquireFrame()) return _Combat; } }

        #region Initialize
        public override void Initialize()
        {
            _preCombatBuffs = createPreCombatBuffs();
            _combatBuffs = createCombatBuffs();
            _Heal = createHeal();
            _Combat = createCombat();
        }
        #endregion

        #region Pre-Combat Buffs
        Composite createPreCombatBuffs()
        {
            return
                new Decorator(ret => Manual,
                    new PrioritySelector(
                        //0 	0.00 	flask,type=winters_bite
                        //1 	0.00 	food,type=black_pepper_ribs_and_shrimp
                        //frost_presence
                        Cast(48266, ret => !buffExists(48266, Me)),
                        //horn_of_winter
                        Cast(57330, ret => !buffExists(57330, Me)),
                        //5 	0.00 	army_of_the_dead
                        //6 	0.00 	mogu_power_potion
                        //7 	0.00 	blood_fury
                        //8 	0.00 	pillar_of_frost
                        //9 	0.00 	raise_dead
                        Cast(45524, ret => gotTarget && targetDistance(Me.CurrentTarget) > 5 * 5 && targetDistance(Me.CurrentTarget) <= 30 * 30 && !debuffExists(45524, Me.CurrentTarget))
                        ));
        }
        #endregion

        #region Combat Buffs
        Composite createCombatBuffs()
        {
            return
                new Decorator(ret => Manual,
                    new PrioritySelector(
                        Cast(45524, ret => gotTarget && targetDistance(Me.CurrentTarget) > 5 * 5 && targetDistance(Me.CurrentTarget) <= 30 * 30 && !debuffExists(45524, Me.CurrentTarget))
                        ));
        }
        #endregion

        #region Heal
        Composite createHeal()
        {
            return
                new Decorator(ret => true,
                    new PrioritySelector(
                        ));
        }
        #endregion

        #region Combat
        Composite createCombat()
        {
            return
                new Decorator(ret => Manual,
                    new PrioritySelector(
                        //A 	1.00 	auto_attack
                        //pillar_of_frost
                        Cast(51271, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 5 * 5 && UseCDs),
                        //C 	1.00 	mogu_power_potion,if=target.time_to_die<=30|(target.time_to_die<=60&buff.pillar_of_frost.up)
                        //D 	7.91 	use_item,name=gauntlets_of_the_allconsuming_maw,if=buff.pillar_of_frost.up
                        //blood_fury
                        Cast(20572, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 5 * 5 && UseCDs),
                        //raise_dead
                        Cast(46584, ret => gotTarget && UseCDs),
                        //G 	2.54 	plague_leech,if=talent.plague_leech.enabled&(dot.blood_plague.remains<1|dot.frost_fever.remains<1)
                        //outbreak,if=!dot.frost_fever.ticking|!dot.blood_plague.ticking
                        Cast(77575, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 30 * 30 && (!debuffExists(55095, Me.CurrentTarget) || !debuffExists(55078, Me.CurrentTarget))),
                        //unholy_blight,if=talent.unholy_blight.enabled&(!dot.frost_fever.ticking|!dot.blood_plague.ticking)
                        Cast(115989, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 10 * 10 && (!debuffExists(55095, Me.CurrentTarget) || !debuffExists(55078, Me.CurrentTarget))),
                        //J 	30.90 	soul_reaper,if=target.health.pct-3*(target.health.pct%target.time_to_die)<=45
                        //K 	0.00 	blood_tap,if=talent.blood_tap.enabled&(target.health.pct-3*(target.health.pct%target.time_to_die)<=45&cooldown.soul_reaper.remains=0)
                        //howling_blast,if=!dot.frost_fever.ticking
                        Cast(49184, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 30 * 30 && !debuffExists(55095, Me.CurrentTarget)),
                        //plague_strike,if=!dot.blood_plague.ticking
                        Cast(45462, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 5 * 5 && !debuffExists(55078, Me.CurrentTarget)),
                        //howling_blast,if=buff.rime.react
                        Cast(49184, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 30 * 30 && buffExists(59052, Me)),
                        //obliterate,if=buff.killing_machine.react
                        Cast(49020, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 5 * 5 && buffExists(51124, Me)),
                        //P 	0.00 	blood_tap,if=talent.blood_tap.enabled&buff.killing_machine.react
                        //Q 	0.00 	blood_tap,if=talent.blood_tap.enabled&buff.blood_charge.stack>10&runic_power>76
                        //frost_strike,if=runic_power>76
                        Cast(49143, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 5 * 5 && runicPower > 76),
                        //obliterate,if=blood=2|frost=2|unholy=2
                        Cast(49020, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 5 * 5 && (bloodRunesActive == 2 || frostRunesActive == 2 || unholyRunesActive == 2)),
                        //T 	7.01 	plague_leech,if=talent.plague_leech.enabled&(dot.blood_plague.remains<3|dot.frost_fever.remains<3)
                        //outbreak,if=dot.frost_fever.remains<3|dot.blood_plague.remains<3
                        Cast(77575, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 30 * 30 && (debuffTimeLeft(55095, Me.CurrentTarget) < 3000 || debuffTimeLeft(55078, Me.CurrentTarget) < 3000)),
                        //unholy_blight,if=talent.unholy_blight.enabled&(dot.frost_fever.remains<3|dot.blood_plague.remains<3)
                        Cast(115989, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 10 * 10 && (debuffTimeLeft(55095, Me.CurrentTarget) < 3000|| debuffTimeLeft(55078, Me.CurrentTarget) < 3000)),
                        //frost_strike,if=talent.runic_empowerment.enabled&frost=0
                        Cast(49143, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 5 * 5 && frostRunesActive == 0),
                        //X 	0.00 	frost_strike,if=talent.blood_tap.enabled&buff.blood_charge.stack<=10
                        //horn_of_winter
                        Cast(57330, ret => true),
                        //Z 	0.00 	frost_strike,if=talent.runic_corruption.enabled&buff.runic_corruption.down
                        //obliterate
                        Cast(49020, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 5 * 5),
                        //b 	0.19 	empower_rune_weapon,if=target.time_to_die<=60&(buff.mogu_power_potion.up|buff.golemblood_potion.up)
                        //c 	0.00 	blood_tap,if=talent.blood_tap.enabled&buff.blood_charge.stack>10&runic_power>=20
                        //frost_strike
                        Cast(49143, ret => gotTarget && targetDistance(Me.CurrentTarget) <= 5 * 5),
                        //e 	4.86 	plague_leech,if=talent.plague_leech.enabled
                        //empower_rune_weapon
                        Cast(47568, ret => gotTarget && UseCDs)
                        ));
        }
        #endregion

        #region Methods

        #region Buff Checks
        public bool buffExists(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }
        #endregion

        #region Cooldown Check
        private Dictionary<WoWSpell, long> Cooldowns = new Dictionary<WoWSpell, long>();
        public void spellUsed(int Spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                WoWSpell result = results.Override ?? results.Original;
                Cooldowns[result] = result.CooldownTimeLeft.Ticks + DateTime.Now.Ticks;
            }
        }
        #endregion

        #region Debuff Checks
        public bool debuffExists(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Debuff);
                if (Results != null)
                    return true;
            }
            return false;
        }
        public double debuffTimeLeft(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Debuff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }
        #endregion

        #region Distance Check
        public double targetDistance(WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.DistanceSqr;
                if (Results != null)
                    return onTarget.DistanceSqr;
            }
            return 0;
        }
        #endregion

        #region Macro Checks
        public bool UseCDs { get { return Convert.ToBoolean(Lua.GetReturnVal<int>("return UseCDs and 0 or 1", 0)); } }
        public bool Manual { get { return Convert.ToBoolean(Lua.GetReturnVal<int>("return Manual and 0 or 1", 0)); } }
        public bool NecroStrike { get { return Convert.ToBoolean(Lua.GetReturnVal<int>("return NecroStrike and 0 or 1", 0)); } }
        #endregion

        #region Target Check
        public bool gotTarget { get { return Me.GotTarget && Me.CurrentTarget != null && (Me.CurrentTarget.IsAlive && !Me.CurrentTarget.IsFriendly || Me.CurrentTarget.Name == "Training Dummy"); } } //<~ Check for Immune auras like the Paladin's Bubble or CC
        #endregion

        #region Rune Checks
        public int deathRunesActive { get { return Me.DeathRuneCount; } }
        public int bloodRunesActive { get { return Me.BloodRuneCount; } }
        public int frostRunesActive { get { return Me.FrostRuneCount; } }
        public int unholyRunesActive { get { return Me.UnholyRuneCount; } }
        #endregion

        #region Runic Power Check
        public double runicPower
        {
            get
            {
                try
                {
                    using (StyxWoW.Memory.AcquireFrame())
                        return Styx.WoWInternals.Lua.GetReturnVal<int>("return UnitPower(\"player\");", 0);
                }
                catch { return 0; }
            }
        }
        #endregion

        #region Spell Casting
        private delegate T Selection<out T> (object Context);
        Composite Cast(int Spell, Selection<bool> reqs = null, Selection<WoWUnit> onTarget = null, bool ignoreCanCast = false)
        {
            using (StyxWoW.Memory.AcquireFrame())
                return
                    new Decorator(ret =>
                        {
                            if (reqs != null && !reqs(ret))
                                return false;
                            if (!ignoreCanCast && !SpellManager.CanCast(Spell, onTarget != null ? onTarget(ret) : Me.CurrentTarget))
                                return false;
                            return true;
                        },
                            new Action(ret =>
                            {
                                WoWSpell castingSpell = Me.CastingSpell;
                                if (castingSpell != null && castingSpell.Id != Spell)
                                    Lua.DoString("SpellStopCasting()");
                                Logging.Write("Casting: " + Spell);
                                SpellManager.Cast(Spell, (onTarget != null ? onTarget(ret) : null));
                            })
                        );
        }
        #endregion

        #endregion
    }
}
